package com.apps.shelper;

import com.apps.sannotation.constraints.NoNull;
import com.apps.sannotation.service.OnRedisCache;
import com.apps.sannotation.service.enums.CacheModel;
import com.apps.saspect.ValidMethod;
import com.apps.sexctption.DataException;
import com.apps.shelper.enums.ClassType;
import lombok.SneakyThrows;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;

/**
 * 类处理工具
 */
public class ClassHelper {

    /**
     * 获取对象的所有成员变量名和值
     * @param object
     * @return  返回一个map key是变量名,object是变量的值
     */
    public  static Map<String,Object> getClassFiledNameValue(Object object)
    {
         if(null==object)
             throw new RuntimeException("传入对象为空");
         Map<String,Object> result=new HashMap<>();

        try {
            Field[] fields = object.getClass().getDeclaredFields();
            for (Field item : fields) {
                if (item.getName().equals("serialVersionUID"))
                    continue;
                if (item.getModifiers() != 2) //如果不是private声明则直接跳过
                    continue;
                item.setAccessible(true);
                result.put(item.getName(),item.get(object));
            }
        }catch (Exception e)
        {
            e.printStackTrace();
        }

        return result;
    }

    /**
     * 获取一个对象的所有属性的名称
     * @param tagetClass
     * @return
     */
    public  static List<String> getClassFiledName(Class<?> tagetClass)
    {
        if(null==tagetClass)
            throw new RuntimeException("传入对象为空");
        List<String> result=new ArrayList<>();

        try {
            Field[] fields = tagetClass.getDeclaredFields();
            for (Field item : fields) {
                if (item.getName().equals("serialVersionUID"))
                    continue;
                if (item.getModifiers() != 2) //如果不是private声明则直接跳过
                    continue;
                item.setAccessible(true);
                result.add(item.getName());
            }
        }catch (Exception e)
        {
            e.printStackTrace();
        }
        return result;
    }


    /**
     * 获取对象某个成员变量的值
     * @param object     对象
     * @param fieldName  成员变量名称
     * @return
     */
    public static Object getFiledValue(Object object,String fieldName)
    {
        if(null==object)
            throw new RuntimeException("传入对象为空");

        try {
            Field[] fields = object.getClass().getDeclaredFields();
            for (Field item : fields) {
                item.setAccessible(true);
                if(item.getName().equals(fieldName))
                    return  item.get(object);

            }
        }catch (Exception e)
        {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 将self的不为null的字段的值复制给target对应的字段,self和target必须是同一个模型
     * @param target
     * @param self
     * @return
     */
    @SneakyThrows
    @ValidMethod
    public static Object CopyNotNullFiled(@NoNull Object target,@NoNull Object self)
    {
        if(!target.getClass().isAssignableFrom(self.getClass()))
            throw new DataException("target和self不是同一个模型");
        Field[] fields = self.getClass().getDeclaredFields();
        for (Field item : fields) {
            //不是私有对象则跳过
            if(item.getModifiers()!=2)
                continue;
            item.setAccessible(true);
            Object obj=item.get(self);
            if(null!=obj)
                item.set(target,obj);
        }
        return target;
    }

    /**
     * 给成员变量设置值
     * @param object
     * @param fieldName
     * @return
     */
    @SneakyThrows
    public static void setFiledValue(String fieldName,Object object,Object value)  {
        if(null==object)
            throw new DataException("传入对象为空");
        Field field=object.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(object,value);
    }

    /**
     * 获取调用者的class,这个方法只能在RedisDataBaseHelper里面使用
     * @return
     */
    public static Class getCallClass()
    {
        try {
            String className=Thread.currentThread() .getStackTrace()[3].getClassName();
            Class t=Class.forName(className);
            return t;
        }catch (Exception e)
        {
            e.printStackTrace();
        }

      return null;
    }

    /**
     * 判刑inter 是否是impl的接口
     * @param inter
     * @param impl
     * @return
     */
   public static boolean isImplement(Class<?> inter,Class<?> impl)
   {
       Class<?>[] interfaces=impl.getInterfaces();
       for(int i=0;i<interfaces.length;i++) {
           if (interfaces[i].equals(inter))
           {
               return true;
           }
       }

       return false;
   }

    /**
     * 获取对象的缓存模式
     * @param cla
     * @return
     */
   public static CacheModel getClassCacheModel(Class<?> cla)
   {
      OnRedisCache redisCache=cla.getAnnotation(OnRedisCache.class);
        if(null!=redisCache)
          return redisCache.model();
        return null;
   }

    /**
     * 用对象的字段生成索引,只要redis缓存用
     * @param object
     * @return
     */
   @SneakyThrows
   public static List<String> getModelIndexes(Object object)
   {
       List<String> result=new ArrayList<>();
       if(null==object)
           throw new RuntimeException("传入模型为空");
       Field[] fields = object.getClass().getDeclaredFields();
       for (Field item : fields)
       {
           item.setAccessible(true);
           Object obj = item.get(object);
           if(item.getModifiers()==2)
               if(null!=obj)
               result.add(item.getName()+"_"+ConversionObjectValue(obj).toString());
               else
               result.add(item.getName()+"_null");
       }

       return result;
   }

    /**
     * 将对象转化成内部使用的值
     * @param object
     * @return
     */
   public static Object ConversionObjectValue(Object object)
   {
       //是LocalDateTime
       if (object.getClass().isAssignableFrom(LocalDateTime.class))
       {
           LocalDateTime result= (LocalDateTime) object;
           return result.toEpochSecond(ZoneOffset.of("+8"));
       }
       //是Date
       if(object.getClass().isAssignableFrom(Date.class))
       {
           Date result= (Date) object;
           return result.getTime();
       }
      return object;
   }

    /**
     * 判断对象的类型
     * @param field
     * @return
     */
    public static ClassType getClassType(Field field)
    {
        //集合
        if(field.getType().isAssignableFrom(ArrayList.class) ||
                field.getType().isAssignableFrom(LinkedList.class) ||
                field.getType().isAssignableFrom(Vector.class) ||
                field.getType().isAssignableFrom(Stack.class))
            return ClassType.LIST;
        //数组
        if(field.getType().isArray())
            return ClassType.ARRAYS;
        //如果是数字
        if (field.getType().isAssignableFrom(Integer.class)   ||
                field.getType().isAssignableFrom(Float.class)     ||
                field.getType().isAssignableFrom(Double.class)) {
            return ClassType.NUMBER;
        }
        //大数类型
        if(field.getType().isAssignableFrom(BigDecimal.class)) {
            return ClassType.BIGDECIMAL;
        }
        if(field.getType().isAssignableFrom(BigInteger.class)) {
            return ClassType.BIGINTEGER;
        }
        //字符串
        if (field.getType().isAssignableFrom(String.class)) {
            return ClassType.STRING;
        }
        return ClassType.NOT;
    }

    /**
     * 重载
     * @param clz
     * @return
     */
    public static ClassType getClassType(Class clz)
    {
        //集合
        if(clz.isAssignableFrom(ArrayList.class) ||
                clz.isAssignableFrom(LinkedList.class) ||
                clz.isAssignableFrom(Vector.class) ||
                clz.isAssignableFrom(Stack.class))
            return ClassType.LIST;
        //数组
        if(clz.isArray())
            return ClassType.ARRAYS;
        //如果是数字
        if (clz.isAssignableFrom(Integer.class)   ||
                clz.isAssignableFrom(Float.class)     ||
                clz.isAssignableFrom(Double.class)) {
            return ClassType.NUMBER;
        }
        //大数类型
        if(clz.isAssignableFrom(BigDecimal.class)) {
            return ClassType.BIGDECIMAL;
        }
        if(clz.isAssignableFrom(BigInteger.class)) {
            return ClassType.BIGINTEGER;
        }
        //字符串
        if (clz.isAssignableFrom(String.class)) {
            return ClassType.STRING;
        }
        return ClassType.NOT;
    }

    public static void main(String... args)  {

       String str="onUpdate(t)";
       String[] arr=str.split("\\(");
       System.out.println(arr[1].replaceAll("\\)",""));
    }
}
